<?php
namespace app\admin\controller;

use app\admin\model\ArticleModel;
use app\common\helper\Uploader;
use think\Controller;
use think\Db;
use think\Exception;

/**
 * 美文爬虫控制器
 * Class Spider
 * @package app\bea\controller
 */
class ArticleSpider extends Controller
{
    const BEAUTIFUL_ARTICLE_INDEX_URL = "https://article1.zmwxxcx.com/article/index1?TagID=%d&Page=%d&refresh=&reids=&Pagesize=%d";
    const BEAUTIFUL_ARTICLE_DETAIL_URL = "https://article1.zmwxxcx.com/article/info?ArticleID=%d";
    const BEAUTIFUL_HOST = "Host: article1.zmwxxcx.com";
    const TAG_ID_SELECTED_VIDEO = 52;// 精选视频首页tag_id
    const TAG_ID_SQUARE_DANCE = 8; // 广场舞tag_id

    /**
     * 从小程序美文图文集拔取数据
     *
     * @return \think\response\Json
     */
    public function beautiful_article_add() {
        if ($this->request->isPost()) {
            $tag_id = input('tag_id/d', '');
            $page = input('page/d', '');
            $cookie = trim(input('cookie', ''));
            //$cookie = 'AppKey=wxcc8b8d49842a4c23;Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3eGNjOGI4ZDQ5ODQyYTRjMjMiLCJhdWQiOiJ3eGNjOGI4ZDQ5ODQyYTRjMjMiLCJqdGkiOiJ3eGNjOGI4ZDQ5ODQyYTRjMjMiLCJpYXQiOjE1NDU2MTUyODMsIm5iZiI6MTU0NTYxNTI4MywiZXhwIjoxNTQ1NjIyNDgzLCJBcHBLZXkiOiJ3eGNjOGI4ZDQ5ODQyYTRjMjMiLCJVc2VySUQiOiI5NTM2MDcxIiwiT3BlbklkIjoib2dxQVcwVnJ1VXBtMHZvd01rN0FndmtHdTYwRSIsIkNyZWF0ZVRpbWUiOiIyMDE4LTEyLTIyIDEwOjI0OjIwIn0.JN32iPdd5W3Q9S_kWBDsDY8xsYwuOAzB4xYTSPAu5II';
            $page_num =  input('page_num/d', 5);
            if (!$tag_id && $page_num > 15) {
                return json(['code' => 0, 'error' => '图文抓取，数据不宜过多，建议page_num为10条左右，视频抓取不做限制']);
            }
            if (empty($page) || empty($cookie)) {
                return json(['code' => 0, 'error' => '请输入拔取的起始页面page及请求的cookie信息']);
            }
            $cookie_arr = explode(';', $cookie);
            $app_key = $cookie_arr[0];
            Db::startTrans();
            try {
                $ch =curl_init();
                $url = sprintf(self::BEAUTIFUL_ARTICLE_INDEX_URL,$tag_id, $page, $page_num);
                curl_setopt($ch,CURLOPT_URL,$url);
                $header = array(self::BEAUTIFUL_HOST);
                //curl_setopt($ch,CURLOPT_,true);
                curl_setopt($ch,CURLOPT_POST,false);
                //curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
                curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
                curl_setopt($ch,CURLOPT_HEADER,true);
                curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
                curl_setopt($ch,CURLOPT_COOKIE,$app_key);

                $content = curl_exec($ch);
                if (!$content) {
                    $err = curl_errno($ch);
                    return json(['code' => 0, 'error' => '首页抓取失败:' . $err]);
                }
                $content_arr = explode('Access-Control-Allow-Credentials: true', $content);
                $result = array_values(json_decode($content_arr[1],true));
                curl_close($ch);

                // 获取详情数据并格式化
                $data = [];
                foreach ($result[2]['Results'] as $index) {
                    $detail = $this->beautiful_detail($index['ArticleID'], $cookie ,$header);
                    if (empty($detail)) {
                        continue;
                    }
                    $data[] = $this->formatData($detail);
                }

                // 写入数据库
                $res = $this->insertDatabase($data);
                if (!$res) {
                    throw new Exception('写入数据库失败！');
                }
                Db::commit();
                return json(['code' => 1, 'msg' => 'success']);
            } catch (\Exception $e) {
                Db::rollback();
                return json(['code' => 0, 'error' => $e->getMessage()]);
            }
        } else {
            $tag_list = [
                self::TAG_ID_SELECTED_VIDEO => '精选视频',
                self::TAG_ID_SQUARE_DANCE => '广场舞视频',
            ];
            $this->assign('tag_list', $tag_list);
            return $this->fetch('article_spider/beautiful_article_add');
        }
    }

    /**
     * 美文图文集拔取详情页
     * @param $id
     * @param $cookie
     * @throws Exception
     */
    private function beautiful_detail($id, $cookie, $header) {
        if (empty($id) || empty($cookie)) {
            throw new Exception('id参数和cookie参数不能为空');
        }
        $ch =curl_init();
        $url = sprintf(self::BEAUTIFUL_ARTICLE_DETAIL_URL, $id);
        curl_setopt($ch,CURLOPT_URL, $url);

        //curl_setopt($ch,CURLOPT_,true);
        curl_setopt($ch,CURLOPT_POST,false);
        //curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($ch,CURLOPT_HEADER,true);
        curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
        curl_setopt($ch,CURLOPT_COOKIE,$cookie);

        $content = curl_exec($ch);
        if (!$content) {
            throw new Exception('请求详情失败:' . curl_errno($ch));
        }
        $content_arr = explode('Access-Control-Allow-Credentials: true', $content);
        $result = array_values(json_decode($content_arr[1],true));
        curl_close($ch);
        return $result[2];
    }

    /**
     * 格式化数据
     *
     * @param $data
     * @return array
     * @throws \Exception
     */
    private function formatData($data) {
        $insert = [
            'token' => ArticleModel::generateToken(),
            'title' => $data['Title'],
            'type' => $data['ArticleType'],
            'created_time' => date('Y-m-d H:i:s', time()),
            'updated_time' => date('Y-m-d H:i:s', time()),
            'click' => mt_rand(1000, 20000),
            'share' => mt_rand(1000, 20000),
            'from_url' => sprintf(self::BEAUTIFUL_ARTICLE_DETAIL_URL, $data['ArticleID']),
            'mp3_url' => $data['BgMusic'],
            'content' => ($data['ArticleType'] == 1)? $this->dealImages($data['Content']):'',
            'video_url' => ($data['ArticleType'] == 1)? '': $data['Content'],
            'cover_img_url' => $data['Cover'],
            'share_title' => $data['ShareString']?$data['ShareString']:$data['Share2String'],
            'status' => ArticleModel::STATUS_LOCK,
            'share_img_url' => $data['Share2Img'],
            'background_url' => $data['BgImage'],
        ];
        return $insert;
    }

    /**
     * 插入数据库
     *
     * @param $data
     * @return bool
     * @throws Exception
     */
    private function insertDatabase($data) {
        $model = new ArticleModel();
        $res = $model->allowField(true)->saveAll($data,false);
        if (!$res) {
            throw new Exception('插入数据库失败');
        }
        return true;
    }

    /**
     * 内容的图片进行处理
     * @param $string
     * @param string $referer 图片请求头referer
     * @return mixed
     * @throws \Exception
     */
    private function dealImages($string, $referer = null)
    {
        // 非背景图片替换
        $pattern = '<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""\']?[\s\t\r\n//]*(?<imgUrl>[^\s\t\r\n""\'<>]*)[^<>]*?/?[\s\t\r\n]*>';
        $string = $this->replaceImage($pattern, $string, $referer);
        // 背景图片替换
        $pattern = '|background-image:[\s]*url\((.+)?\);|Ui';
        $string = $this->replaceImage($pattern, $string, $referer);
        return $string;
    }

    /**
     * 上传并替换图片
     *
     * @param string $pattern 匹配模式
     * @param string $string 目标字符串
     * @param string $referer 请求原始url (图片请求头referer)
     * @return mixed
     * @throws \Exception
     */
    private function replaceImage($pattern, $string, $referer)
    {
        preg_match_all($pattern, $string, $matches);
        $arr = $this->clearQuote($matches[1]);
        foreach ($arr as $key => $item) {
            $res = $this->uploadQiNiu($item, $referer);
            if (!$res) {
                throw new \Exception($this->error_msg?$this->error_msg:'图片上传失败！');
            }
            $string = str_replace($matches[1][$key], $res, $string);
        }
        return $string;
    }

    /**
     * 去除空格
     * @param $inarr3
     * @return array
     */
    private function clearQuote($inarr3)
    {
        $list = [];
        foreach ($inarr3 as $index => $item) {
            $list[$index] = str_replace(['&quot;', '&amp;quot;'], ['', ''], $item);
        }
        return $list;
    }

    // 上传处理
    private function uploadQiNiu($image, $from_url)
    {
        $pos = strpos($image, 'http', 0);
        $base_pos = strpos($image, 'data:image/', 0);
        if ($pos === 0) {
            if ($from_url) {// 防盗链的图片下载，再上传七牛
                $fileName = $this->http_get_data($image, $from_url);
                $res = $this->localUpload($fileName);
            } else {// 远程上传
                $res = $this->remoteUpload($image);
            }
        } else if ($base_pos === 0) {
            $res = $this->saveBase64($image); // base64上传
        } else {
            $filePath = str_replace('\\', '/', dirname(THINK_PATH) . '/' . $image);
            $res = $this->localUpload($filePath);// 默认本地上传
        }
        return $res;
    }

    private function saveBase64($base64, $key = NULL)
    {
        $uploader = new Uploader();
        if ($res = $uploader->uploadBase64($base64, $key)) {
            return $res;
        }
        return false;
    }

    private function remoteUpload($image_url)
    {
        $uploader = new Uploader();
        if ($res = $uploader->uploadFromRemote($image_url, 'photo_album_bless_' . time() . rand(101, 18989))) {
            return $res;
        }
        return false;
    }

    private function localUpload($image)
    {
        $uploader = new Uploader();
        if ($res = $uploader->uploadQiniu($image)) {
            return $res;
        }
        return false;
    }

    /**
     * 将带防盗链的图片先下载到本地
     *
     * @param $url
     * @param null $referer
     * @return bool|string
     */
    function http_get_data($url, $referer = null)
    {
        if (!$referer) { // 请求的页面url，第一个请求url
            $referer = $url;
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_HTTPGET, true);
        curl_setopt($ch, CURLOPT_REFERER, $referer);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36');

        ob_start();
        $ob_stream = curl_exec($ch);
        echo $ob_stream;
        $return_content = ob_get_contents();
        ob_end_clean();
        curl_close($ch);
        $filename = str_replace('\\', '/', dirname(THINK_PATH) . '/public_html/uploads/temp/' . time().'jpg');
        file_put_contents($filename, $return_content);

        return $filename;
    }
}